package com.ruoyi.pack.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.pack.domain.WayBill;
import com.ruoyi.pack.mapper.WayBillMapper;
import com.ruoyi.pack.service.IWayBillService;
import com.ruoyi.pack.service.ITransportPlanService;
import org.springframework.jdbc.core.JdbcTemplate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Collection;
import java.util.ArrayList;
import java.io.Serializable;

/**
 * 运单Service业务层处理
 *
 * @Author: jeecg-boot
 * @Date: 2025-01-26
 * @Version: V1.0
 */
@Service
public class WayBillServiceImpl extends ServiceImpl<WayBillMapper, WayBill> implements IWayBillService {

    private static final Logger log = LoggerFactory.getLogger(WayBillServiceImpl.class);

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ITransportPlanService transportPlanService;

    @Value("${server.port:8080}")
    private String serverPort;

    /**
     * 查询运单列表
     *
     * @param wayBill 运单查询条件
     * @return 运单集合
     */
    @Override
    public List<WayBill> selectWayBillList(WayBill wayBill) {
        log.info("构建运单查询条件，参数：{}", wayBill);

        LambdaQueryWrapper<WayBill> queryWrapper = new LambdaQueryWrapper<>();
        if (wayBill.getLocatorId() != null && wayBill.getLocatorId() == -1 && StringUtils.equals(wayBill.getLocatorCode(), "-1")) {
            // 如果定位器ID和定位器编码都为-1，则查询所有未绑定的运单
            log.info("使用特殊查询条件：查询未绑定的运单");
            queryWrapper
                // 简化查询条件：只查询locatorId为null或0的记录
                .and(wrapper -> wrapper.isNull(WayBill::getLocatorId).or().eq(WayBill::getLocatorId, 0))
                // 添加基本查询条件
                .eq(StringUtils.isNotEmpty(wayBill.getBillStatus()), WayBill::getBillStatus, wayBill.getBillStatus());
        } else {
            // 使用Lambda表达式构建查询条件，自动处理null和空字符串
            queryWrapper
                    .like(StringUtils.isNotEmpty(wayBill.getBillNo()), WayBill::getBillNo, wayBill.getBillNo())
                    .eq(StringUtils.isNotEmpty(wayBill.getBillStatus()), WayBill::getBillStatus, wayBill.getBillStatus())
                    .like(StringUtils.isNotEmpty(wayBill.getSenderName()), WayBill::getSenderName, wayBill.getSenderName())
                    .like(StringUtils.isNotEmpty(wayBill.getReceiverName()), WayBill::getReceiverName, wayBill.getReceiverName())
                    .like(StringUtils.isNotEmpty(wayBill.getGoodsName()), WayBill::getGoodsName, wayBill.getGoodsName())
                    .eq(StringUtils.isNotEmpty(wayBill.getGoodsType()), WayBill::getGoodsType, wayBill.getGoodsType())
                    .eq(StringUtils.isNotEmpty(wayBill.getTransportType()), WayBill::getTransportType, wayBill.getTransportType())
                    .eq(StringUtils.isNotEmpty(wayBill.getPayType()), WayBill::getPayType, wayBill.getPayType())
                    .eq(StringUtils.isNotEmpty(wayBill.getSenderCity()), WayBill::getSenderCity, wayBill.getSenderCity())
                    .eq(StringUtils.isNotEmpty(wayBill.getReceiverCity()), WayBill::getReceiverCity, wayBill.getReceiverCity())
                    .like(StringUtils.isNotEmpty(wayBill.getContactA()), WayBill::getContactA, wayBill.getContactA())
                    .like(StringUtils.isNotEmpty(wayBill.getContactB()), WayBill::getContactB, wayBill.getContactB())
                    .like(StringUtils.isNotEmpty(wayBill.getPhoneA()), WayBill::getPhoneA, wayBill.getPhoneA())
                    .like(StringUtils.isNotEmpty(wayBill.getPhoneB()), WayBill::getPhoneB, wayBill.getPhoneB())
                    .ge(StringUtils.isNotEmpty(wayBill.getBeginTime()), WayBill::getCreateTime, wayBill.getBeginTime())
                    .le(StringUtils.isNotEmpty(wayBill.getEndTime()), WayBill::getCreateTime, wayBill.getEndTime() + " 23:59:59")
                    // 添加定位器绑定状态查询条件
                    .eq(wayBill.getLocatorId() != null, WayBill::getLocatorId, wayBill.getLocatorId())
                    .eq(StringUtils.isNotEmpty(wayBill.getLocatorCode()), WayBill::getLocatorCode, wayBill.getLocatorCode());
        }

        // 注意：不在QueryWrapper中设置排序，让PageHelper来处理排序
        // RuoYi框架中排序由PageHelper统一管理，避免冲突
        // 但是需要提供一个默认排序以确保查询稳定性
        queryWrapper.orderByDesc(WayBill::getCreateTime);

        log.info("构建的查询条件SQL：{}", queryWrapper.getSqlSegment());

        // 使用Mapper查询以支持PageHelper分页
        log.info("开始执行查询...");
        List<WayBill> result = baseMapper.selectList(queryWrapper);
        log.info("查询执行完成，结果数量：{}", result.size());
        return result;
    }


    // ==================== 位置跟踪相关方法实现 ====================

    @Override
    public WayBill selectWayBillByLocatorId(Long locatorId) {
        if (locatorId == null) {
            return null;
        }

        QueryWrapper<WayBill> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("locator_id", locatorId);

        List<WayBill> wayBills = this.list(queryWrapper);
        return wayBills.isEmpty() ? null : wayBills.get(0);
    }

    @Override
    public WayBill selectWayBillByLocatorCode(String locatorCode) {
        if (StringUtils.isEmpty(locatorCode)) {
            log.warn("定位器编码为空，无法查询绑定的运单");
            return null;
        }

        log.debug("开始查询定位器编码 {} 绑定的运单", locatorCode);

        QueryWrapper<WayBill> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("locator_code", locatorCode);
        queryWrapper.eq("bill_status", "运输中");

        List<WayBill> wayBills = this.list(queryWrapper);

        if (wayBills.isEmpty()) {
            log.warn("定位器编码 {} 未绑定任何运单", locatorCode);
            return null;
        } else {
            WayBill wayBill = wayBills.get(0);
            log.info("定位器编码 {} 绑定的运单ID: {}, 运单编号: {}", locatorCode, wayBill.getId(), wayBill.getBillNo());
            return wayBill;
        }
    }

    @Override
    public int updateWayBillLocation(WayBill wayBill) {
        if (wayBill == null || StringUtils.isEmpty(wayBill.getId())) {
            return 0;
        }

        try {
            boolean result = this.updateById(wayBill);
            return result ? 1 : 0;
        } catch (Exception e) {
            log.error("更新运单位置信息失败", e);
            return 0;
        }
    }

    @Override
    @Transactional
    public int bindLocator(String wayBillId, Long locatorId, String locatorCode) {
        if (StringUtils.isEmpty(wayBillId) || locatorId == null) {
            log.warn("运单ID或定位器ID为空，无法执行绑定操作");
            return 0;
        }

        try {
            log.info("开始执行运单绑定定位器操作，运单ID: {}, 定位器ID: {}, 定位器编码: {}", wayBillId, locatorId, locatorCode);

            // 1. 更新运单表
            WayBill wayBill = this.getById(wayBillId);
            if (wayBill == null) {
                log.warn("运单不存在，运单ID: {}", wayBillId);
                return 0;
            }

            wayBill.setLocatorId(locatorId);
            wayBill.setLocatorCode(locatorCode);
            wayBill.setBillStatus("运输中");
            boolean wayBillResult = this.updateById(wayBill);
            if (!wayBillResult) {
                log.error("更新运单表失败，运单ID: {}", wayBillId);
                return 0;
            }

            log.info("运单表更新成功，运单ID: {}", wayBillId);

            // 2. 通过HTTP接口更新定位器表的containerId字段
            try {
                updateLocatorContainerId(locatorId, Long.parseLong(wayBillId));
                log.info("定位器表更新成功，定位器ID: {}, containerId: {}", locatorId, wayBillId);
            } catch (Exception e) {
                log.error("更新定位器containerId失败", e);
                // 不阻断主流程，只记录错误
            }

            // 3. 生成运输计划
            try {
                int planCount = transportPlanService.generateTransportPlanForWayBill(wayBillId);
                log.info("运输计划生成成功，运单ID: {}, 生成记录数: {}", wayBillId, planCount);

                // 4. 更新起点到达时间为当前时间（绑定定位器即表示开始运输）
                updateTransportPlanStartPointArrivalTime(wayBill.getBillNo());
                log.info("绑定定位器成功，起点到达时间已更新为当前时间，运单编号: {}", wayBill.getBillNo());

            } catch (Exception e) {
                log.error("生成运输计划失败，运单ID: {}", wayBillId, e);
                // 不阻断主流程，只记录错误
            }

            log.info("运单绑定定位器操作成功完成，运单ID: {}, 定位器ID: {}", wayBillId, locatorId);
            return 1;

        } catch (Exception e) {
            log.error("绑定运单定位器失败，运单ID: {}, 定位器ID: {}", wayBillId, locatorId, e);
            return 0;
        }
    }

    @Override
    public int unbindLocator(String wayBillId) {
        if (StringUtils.isEmpty(wayBillId)) {
            return 0;
        }

        try {
            WayBill wayBill = this.getById(wayBillId);
            if (wayBill == null) {
                return 0;
            }

            // 获取要解绑的定位器ID
            Long locatorId = wayBill.getLocatorId();

            wayBill.setLocatorId(0L);         // 设置locatorId为0
            wayBill.setLocatorCode(null);    // 设置locatorCode为null

            boolean result = this.updateById(wayBill);

            // 更新定位器表的container_id字段为-1
            if (result && locatorId != null && locatorId != 0L) {
                try {
                    updateLocatorContainerId(locatorId, -1L);
                    log.info("定位器表解绑成功，定位器ID: {}, containerId设置为-1", locatorId);
                } catch (Exception e) {
                    log.error("更新定位器containerId失败", e);
                    // 不阻断主流程，只记录错误
                }
            }

            return result ? 1 : 0;
        } catch (Exception e) {
            log.error("解绑运单定位器失败", e);
            return 0;
        }
    }



    @Override
    public List<WayBill> selectDelayedWayBills() {
        QueryWrapper<WayBill> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("delay_status", "延迟");
        queryWrapper.orderByDesc("delay_hours");

        return this.list(queryWrapper);
    }

    @Override
    public List<WayBill> selectPendingHandoverWayBills() {
        QueryWrapper<WayBill> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("handover_status", "待交接");
        queryWrapper.orderByAsc("arrival_time");

        return this.list(queryWrapper);
    }

    @Override
    @Transactional
    public boolean forceUnbindLocator(String wayBillId) {
        if (StringUtils.isEmpty(wayBillId)) {
            log.warn("运单ID为空，无法执行强制解绑操作");
            return false;
        }

        try {
            log.info("开始执行强制解绑操作，运单ID: {}", wayBillId);

            // 使用UpdateWrapper强制设置NULL值
            UpdateWrapper<WayBill> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", wayBillId)
                        .set("locator_id", 0)
                        .set("locator_code", null);  // 强制设置为NULL

            boolean result = this.update(updateWrapper);

            if (result) {
                log.info("强制解绑运单定位器成功，运单ID: {}", wayBillId);
            } else {
                log.error("强制解绑运单定位器失败，运单ID: {}", wayBillId);
            }

            return result;

        } catch (Exception e) {
            log.error("强制解绑运单定位器异常，运单ID: {}", wayBillId, e);
            return false;
        }
    }

    /**
     * 通过SQL直接更新定位器的containerId字段
     */
    private void updateLocatorContainerId(Long locatorId, Long containerId) {
        try {
            String sql = "UPDATE pack_locator SET container_id = ?, update_time = NOW() WHERE locator_id = ? AND del_flag = '0'";
            int rowsAffected = jdbcTemplate.update(sql, containerId, locatorId);

            if (rowsAffected > 0) {
                log.info("通过SQL直接更新定位器containerId成功，定位器ID: {}, containerId: {}", locatorId, containerId);
            } else {
                log.warn("SQL更新定位器containerId失败，可能定位器不存在，定位器ID: {}", locatorId);
            }

        } catch (Exception e) {
            log.error("SQL更新定位器containerId异常，定位器ID: {}, containerId: {}", locatorId, containerId, e);
            throw e;
        }
    }

    /**
     * 更新运输计划表中起点数据的到达时间
     *
     * @param billNo 运单编号
     */
    private void updateTransportPlanStartPointArrivalTime(String billNo) {
        if (StringUtils.isEmpty(billNo)) {
            log.warn("运单编号为空，无法更新运输计划起点到达时间");
            return;
        }

        try {
            // 通过SQL直接更新起点的到达时间为当前时间（起点数据只有一条）
            String sql = "UPDATE transport_plan SET arrival_time = NOW(), update_time = NOW() " +
                         "WHERE bill_no = ? AND node_type = '起点'";

            int rowsAffected = jdbcTemplate.update(sql, billNo);

            if (rowsAffected > 0) {
                log.info("更新起点运输计划到达时间成功，运单编号: {}, 影响行数: {}", billNo, rowsAffected);

                if (rowsAffected > 1) {
                    log.warn("发现多条起点运输计划被更新，运单编号: {}, 数量: {}", billNo, rowsAffected);
                }
            } else {
                log.warn("未找到需要更新的起点运输计划，运单编号: {}", billNo);
            }

        } catch (Exception e) {
            log.error("SQL更新起点运输计划到达时间异常，运单编号: {}", billNo, e);
            throw e;
        }
    }

    @Override
    public boolean removeByIds(Collection<?> idList) {
        if (idList == null || idList.isEmpty()) {
            log.warn("删除运单时，ID列表为空");
            return false;
        }

        try {
            log.info("开始逻辑删除运单，ID列表：{}", idList);

            // 查询要删除的运单信息
            List<WayBill> wayBills = this.listByIds((Collection<? extends Serializable>) idList);
            if (wayBills.isEmpty()) {
                log.warn("未找到要删除的运单，ID列表：{}", idList);
                return false;
            }

            // 检查运单状态，只允许删除"待发货"状态的运单
            List<String> invalidWayBills = new ArrayList<>();
            for (WayBill wayBill : wayBills) {
                if (!"待发货".equals(wayBill.getBillStatus()) && !"1".equals(wayBill.getBillStatus())) {
                    invalidWayBills.add(wayBill.getBillNo());
                }
            }

            if (!invalidWayBills.isEmpty()) {
                log.warn("存在不允许删除的运单，运单号：{}，状态不是'待发货'", invalidWayBills);
                throw new RuntimeException("以下运单状态不是'待发货'，不允许删除：" + String.join(", ", invalidWayBills));
            }

            // 执行逻辑删除
            boolean result = super.removeByIds(idList);
            if (result) {
                log.info("运单逻辑删除成功，ID列表：{}", idList);
            } else {
                log.error("运单逻辑删除失败，ID列表：{}", idList);
            }
            return result;

        } catch (Exception e) {
            log.error("删除运单异常，ID列表：{}，错误信息：{}", idList, e.getMessage(), e);
            throw new RuntimeException("删除运单失败：" + e.getMessage(), e);
        }
    }
}
